#!/bin/bash

# This script reads kernel information from the GRUB menu to pass to "kexec".
# Save a script as, e.g., /usr/local/sbin/kexec-reboot and make it executable
# using chmod +x.

# The script takes an item number as its first parameter. E.g., to boot the
# first item in the GRUB menu, type:
#     kexec-reboot 1

# Alternatively, if no number is given, the script will interactively prompt
# for a number.

# The error checking is very basic.
# Written by Isaac G, 2010
# Modified by Greg Fitzgerald, 2011
# Ripped from the Arch Wiki "kexec" page 7 May 2012:
#     https://wiki.archlinux.org/index.php?title=kexec

die ()
{
   tput setaf 1 # Red text
   echo "Error: $@" >&2
   tput sgr0 # Reset
   exit 1
}
 
(( UID != 0 )) && die "You need to be superuser"

probe ()
{
   test -e "$1" || return
   GRUB_CONFIG="$1"
   GRUB_TITLE="$2"  # Command for menu item name
   GRUB_KERNEL="$3"  # Command for boot image
}

# Config file for Grub 2 overrides original "legacy" one
probe /boot/grub/grub.cfg menuentry linux ||
probe /boot/grub/menu.lst title kernel ||
die "No Grub configuration found"

# Use the first parameter or show a menu if none is specified
unset number
if [[ $1 ]] ; then
   # Make sure the selected number is an integer
   [[ $1 = *[^0-9]* ]] && die "The selected parameter is not a number"
   number=$1
else
   # Nothing selected; pull up a list of options from the grub menu
   oldIFS="$IFS"
   IFS=$'\n'

   # Get the menu items
   options=( $(awk '$1 == "'"$GRUB_TITLE"'" {for (i = 2; i <= NF; i++) printf "%s ", $i; printf "\n";}' "$GRUB_CONFIG" ) )

   # Ask the user to select one
   select title in "${options[@]}" ; do
       for ((i = 0; i < ${#options[@]}; i++)); do
           [[ $title == "${options[i]}" ]] && number=$((i + 1)) && break
       done
       [[ $number ]] && break
   done

   IFS="$oldIFS"
fi

unset kernel
unset initrd
unset append
item=0

# Parse GRUB's configuration file
while read key val extra; do
   [[ $key = "$GRUB_TITLE" ]] && ((item++)) # Count the number of menu items
   (( item == number )) || continue   # Wait until the right number
   [[ $key = "$GRUB_KERNEL" ]] && kernel="$val" && append="$extra"
   [[ $key = "initrd" ]] && initrd="$val"
done < "$GRUB_CONFIG"

[[ $kernel ]] || die "No such kernel with that number"

# http://stackoverflow.com/questions/2167558/give-the-mount-point-of-a-path
root="$(df /boot | tail -n 1 | awk '{ print $NF}')"

set -- "$root$kernel"
[[ -n "${initrd+set}" ]] && set -- "$@" --initrd="$root$initrd"
set -- "$@" --append="$append"
kexec "$@"
